﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Bubbles
{
    public partial class PlayGround : UserControl
    {
        Bubble[,] _bubbleArea;
        Grid _grid;
        MediaElement _sound;
        bool _started = false;

        public PlayGround()
        {
            InitializeComponent();

            this.Loaded += (s, e) =>
                {
                    CreatePlayground();
                }; 

            // Trick to initialize ;-)
            Settings.Level = Settings.Level;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (this.Visibility == Visibility.Collapsed || !_started)
            {
                return base.ArrangeOverride(finalSize);
            }

            Size size = finalSize;

            double width2 = size.Width > size.Height ? size.Height : size.Width;
            double height2 = size.Width > size.Height ? size.Height : size.Width;

            _grid.Height = height2;
            _grid.Width = width2;

            return base.ArrangeOverride(finalSize);
        }

        #region Events

        public event EventHandler GameFinished;
        public event BubblesRemovedEventHandler BubblesRemoved;

        #endregion

        #region Eventhandler

        void bubble_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Bubble bubble = sender as Bubble;

            DoBubbleClick(bubble);
        }

        #endregion

        public void Start()
        {
            _started = true;
            CreatePlayground();
        }

        private void CreatePlayground()
        {
            #region Create Bubble Area

            // Create Grid
            _grid = new Grid();
            this.Content = _grid;
            
            // Create Columns
            double width = 1 / Convert.ToDouble(Settings.DimensionX);
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                ColumnDefinition cd = new ColumnDefinition();

                cd.Width = new GridLength(width, GridUnitType.Star);
                _grid.ColumnDefinitions.Add(cd);
            }

            // Create Rows
            double height = 1 / Convert.ToDouble(Settings.DimensionY);
            for (int y = 0; y < Settings.DimensionY; y++)
            {
                RowDefinition cd = new RowDefinition();
                cd.Height = new GridLength(height, GridUnitType.Star);
                _grid.RowDefinitions.Add(cd);
            }

            #endregion

            #region Create Bubbles

            // Create Bubble
            _bubbleArea = new Bubble[Settings.DimensionX, Settings.DimensionY];
            Random rnd = new Random();
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int y = 0; y < Settings.DimensionY; y++)
                {
                    // Create Random Bubble
                    Bubble bubble = new Bubble();
                    bubble.MouseLeftButtonDown += bubble_MouseLeftButtonDown;

                    Color color;
                    switch (rnd.Next(5))
                    {
                        case 0:
                            color = Colors.Blue;
                            break;

                        case 1:
                            color = Colors.Red;
                            break;

                        case 2:
                            color = Colors.Yellow;
                            break;

                        case 3:
                            color = Colors.Green;
                            break;

                        case 4:
                            color = Colors.Orange;
                            break;

                        default:
                            color = Colors.Black;
                            break;
                    }
                    bubble.BubbleColor = color;
                    _bubbleArea[x, y] = bubble;
                }
            }

            #endregion

            #region Display Bubbles

            // Display Bubbles
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int y = 0; y < Settings.DimensionY; y++)
                {
                    Bubble bubble = _bubbleArea[x, y];
                    bubble.Margin = new Thickness(Settings.Margin);
                    bubble.SetValue(Grid.ColumnProperty, x);
                    bubble.SetValue(Grid.RowProperty, y);
                    _grid.Children.Add(bubble);
                }
            }

            #endregion

            #region Add Sound

            _sound = new MediaElement();
            _sound.Source = new Uri("bubblepop.wma", UriKind.Relative);
            _sound.AutoPlay = false;
            _sound.Volume = 1;
            _grid.Children.Add(_sound);

            #endregion 
        }

        private void DoBubbleClick(Bubble bubble)
        {
            // Find Surrounding Bubbles
            List<Bubble> surroundingBubbles = new List<Bubble>();
            GetSurroundingBubbles(bubble, surroundingBubbles);
            surroundingBubbles.Add(bubble);

            if (surroundingBubbles.Count > 1)
            {
                RemoveBubbles(surroundingBubbles);
            }
        }

        private void RemoveBubbles(List<Bubble> surroundingBubbles)
        {
            if (surroundingBubbles.Count == 0)
            {
                return;
            }

            _sound.Stop();

            if (BubblesRemoved != null)
            {
                BubblesEventArgs args = new BubblesEventArgs();
                args.BubbleCount = surroundingBubbles.Count;
                BubblesRemoved(this, args);
            }

            _sound.Play();
            
            foreach (Bubble b in surroundingBubbles)
            {
                for (int x = 0; x < Settings.DimensionX; x++)
                {
                    for (int y = 0; y < Settings.DimensionY; y++)
                    {
                        if (_bubbleArea[x, y] == b)
                        {
                            _bubbleArea[x, y] = null;
                            b.MouseLeftButtonDown -= bubble_MouseLeftButtonDown;
                            _grid.Children.Remove(b);
                        }
                    }
                }
            }
            LetBubblesFall();
        }

        private void LetBubblesFall()
        {
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int i = 0; i < Settings.DimensionY - 1; i++)
                {
                    for (int y = Settings.DimensionY - 2; y >= 0; y--)
                    {
                        Bubble bubble = _bubbleArea[x, y];

                        if (_bubbleArea[x, y + 1] == null)
                        {
                            // Move Bubble down
                            _bubbleArea[x, y + 1] = _bubbleArea[x, y];
                            _bubbleArea[x, y] = null;
                        }
                    }
                }
            }
            BubblesToTheRight();
        }

        private void BubblesToTheRight()
        {
            for (int y = 0; y < Settings.DimensionY; y++)
            {
                for (int i = 0; i < Settings.DimensionY - 1; i++)
                    for (int x = 0; x < Settings.DimensionY - 1; x++)
                    {
                        if (_bubbleArea[x + 1, y] == null)
                        {
                            if (_bubbleArea[x, y] != null)
                            {
                                _bubbleArea[x + 1, y] = _bubbleArea[x, y];
                                _bubbleArea[x, y] = null;
                            }
                        }
                    }
            }
            UpdateBubbles();
        }

        private void UpdateBubbles()
        {
            // Display Bubbles
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int y = 0; y < Settings.DimensionY; y++)
                {
                    Bubble bubble = _bubbleArea[x, y];
                    if (bubble != null)
                    {
                        bubble.SetValue(Grid.ColumnProperty, x);
                        bubble.SetValue(Grid.RowProperty, y);
                    }
                }
            }
            CheckForEnd();
        }

        private void CheckForEnd()
        {
            bool finished = true;
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int y = 0; y < Settings.DimensionY; y++)
                {
                    Bubble bubble = _bubbleArea[x, y];

                    List<Bubble> surroundingBubbles = new List<Bubble>();
                    GetSurroundingBubbles(bubble, surroundingBubbles);

                    if (surroundingBubbles.Count > 0)
                    {
                        finished = false;
                        break;
                    }
                }
            }
            if (finished)
            {
                if (GameFinished != null)
                {
                    GameFinished(this, EventArgs.Empty);
                }
            }
        }

        private void GetSurroundingBubbles(Bubble bubble, List<Bubble> surroundingBubbles)
        {
            if (bubble == null)
            {
                return;
            }

            int bubbleX = -1;
            int bubbleY = -1;

            // Display Bubbles
            for (int x = 0; x < Settings.DimensionX; x++)
            {
                for (int y = 0; y < Settings.DimensionY; y++)
                {
                    if (_bubbleArea[x, y] == bubble)
                    {
                        bubbleX = x;
                        bubbleY = y;
                        break;
                    }
                }
            }

            Bubble bubbleToCheck;

            // Left Bubble
            if (bubbleX > 0 && bubbleY != -1)
            {
                bubbleToCheck = _bubbleArea[bubbleX - 1, bubbleY];
                CheckBubble(bubbleToCheck, bubble, surroundingBubbles);
            }

            // Right Bubble
            if (bubbleX < Settings.DimensionX - 1 && bubbleY != -1)
            {
                bubbleToCheck = _bubbleArea[bubbleX + 1, bubbleY];
                CheckBubble(bubbleToCheck, bubble, surroundingBubbles);
            }

            // Top Bubble
            if (bubbleX != -1 && bubbleY > 0)
            {
                bubbleToCheck = _bubbleArea[bubbleX, bubbleY - 1];
                CheckBubble(bubbleToCheck, bubble, surroundingBubbles);
            }

            // Bottom Bubble
            if (bubbleX != -1 && bubbleY < Settings.DimensionY - 1)
            {
                bubbleToCheck = _bubbleArea[bubbleX, bubbleY + 1];
                CheckBubble(bubbleToCheck, bubble, surroundingBubbles);
            }
        }

        private void CheckBubble(Bubble bubbleToCheck, Bubble bubble, List<Bubble> surroundingBubbles)
        {
            if (bubbleToCheck == null)
            {
                return;
            }

            if (bubbleToCheck.BubbleColor == bubble.BubbleColor)
            {
                if (!surroundingBubbles.Contains(bubbleToCheck))
                {
                    surroundingBubbles.Add(bubbleToCheck);
                    GetSurroundingBubbles(bubbleToCheck, surroundingBubbles);
                }
            }
        }
    }
}